<?php

class Logger {
    const FATAL = 1;
    const ERROR = 2;
    const WARNING = 3;
    const DEBUG = 4;
    const NOTICE = 5;

    public static function fatal($msg, $object = null) {
        Logger::log(self::FATAL, $msg, $object);
    }

    public static function error($msg, $object = null) {
        Logger::log(self::ERROR, $msg, $object);
    }

    public static function warning($msg, $object = null) {
        Logger::log(self::WARNING, $msg, $object);
    }

    public static function debug($msg, $object = null) {
        Logger::log(self::DEBUG, $msg, $object);
    }

    public static function notice($msg, $object = null) {
        Logger::log(self::NOTICE, $msg, $object);
    }

    public static function log($level, $msg, $object) {

        $levelTxt = '';

        switch ($level) {
            case self::FATAL:
                $levelTxt = 'fatal';
                break;
            case self::ERROR:
                $levelTxt = 'error';
                break;
            case self::WARNING:
                $levelTxt = 'warning';
                break;
            case self::DEBUG:
                $levelTxt = 'debug';
                break;
            case self::NOTICE:
                $levelTxt = 'notice';
                break;
        }

        $backTraces = debug_backtrace();
        $time = date('d.m.Y h:i:s:u');
        $errMsg = $traceMsg = $file = $line = '';
        $idx = 1;

        foreach ($backTraces as $i => $b) {

            if (empty($errMsg) && isset($b['class']) && $b['class'] == 'Logger') {
                if ($b['function'] != 'log') {
                    $line = $b['line'];
                    $file = $b['file'];
                }
                continue;
            }

            if (empty($errMsg) && ((isset($b['class']) && $b['class'] != 'Logger') || !isset($b['class']))) {
                $errMsg = "[{$time}] [$levelTxt] $msg in {$file}:{$b['function']} on line {$line}";

                if (!empty($_SERVER['REQUEST_URI'])) {
                    $errMsg .= ' from: ' . $_SERVER['REQUEST_URI'];
                }
            }

            if ($level <= self::ERROR) {
                $c = isset($b['class']) ? $b['class'] : '';
                $t = isset($b['type']) ? $b['type'] : '';
                $f = isset($b['file']) ? $b['file'] : '';
                $l = isset($b['line']) ? $b['line'] : '';
                $fu = isset($b['function']) ? $b['function'] : '';
                $a = isset($b['args']) && !empty($b['args']) ? implode('", "', $b['args']) : array();

                $location = (empty($f) && empty($l)) ? '' : $f.':'.$l.' ';

                if (empty($fu)) {
                    $trace = $location.$c.$t;
                } else {
                    $trace = $location.$c.$t.$fu.'("'.$a.'")';
                }

                $traceMsg .= "  $idx. $trace\n";
                $idx++;
            }
        }

        if ($level <= self::ERROR) {
            $traceMsg = "\n[Stack Trace]\n".$traceMsg;
        }

        if ($object !== null) {
            $errMsg .= "\n" . self::dump_one_object($object);
        }

        error_log($errMsg.$traceMsg);
    }

    private static function dump_one_object($object, $indent = '    ') {
        if (!is_object($object) && !is_array($object)) {
            return $object;
        }

        $output = '';

        foreach ($object as $key => $value) {
            $output .= $indent . "|$key|=> ";
            if (is_array($value)) {
                if (sizeof($value) == 0) {
                  $output .= "|__EMPTY__|\n";
                  continue;
                }
                $output .= "\n";
                $output .= self::dump_one_object($value, $indent."    ");
            } else {
                if ($value) {
                    if ($value instanceof SimpleXMLElement) {
                        $output .= "|SimpleXmlData|";
                    } else if (is_object($value)) {
                        $output = get_class($value);
                    } else {
                        $output .= "|$value|";
                    }
                } else if ($value === NULL) {
                    $output .= "|__NULL__|";
                } else if ($value === false) {
                    $output .= "|__FALSE__|";
                } else {
                    $output .= "|__EMPTY__|";
                }
            }
            $output .= "\n";
        }

        return $output;
    }
}